Medium
Design an EventEmitter
class. This interface is similar (but with some differences) to the one found in Node.js or the Event Target interface of the DOM. The EventEmitter
should allow for subscribing to events and emitting them.
Your EventEmitter
class should have the following two methods:
subscribe
are referentially identical.subscribe
method should also return an object with an unsubscribe
method that enables the user to unsubscribe. When it is called, the callback should be removed from the list of subscriptions and undefined
should be returned.設計一個EventEmitter
類別,此介面與 Node.js 或 DOM 的目標事件介面類似(但有一些差異)。EventEmitter
應該允許訂閱事件以及觸發事件。
EventEmitter
類別應該有以下兩種方法:
subscribe
方法應該回傳一個包含unsubscribe
方法的物件使用戶能夠取消訂閱,當它被呼叫時,回調函數應該從訂閱列表中刪除,並且應該返回undefined
。class EventEmitter {
//`constructor()`建構函數邏輯:一個事件可以註冊多個監聽器。
//建構函示使用Map儲存鍵值對 [event,cbs]的集合
constructor() {
this.events = new Map();
}
//註冊監聽
//訪問 鍵值對 取得 屬性值 陣列cbs,將回調函數push至陣列cbs內。
//(如key不存在添加一個屬性值為[]的初始化的鍵值對)
subscribe(event,cb) {
if (!this.events.has(event)) {
this.events.set(event, []);
}
const cbs = this.events.get(event);
cbs.push(cb);
//回傳取消訂閱的方法`unsubscribe`
// 取得 cb 在 cbs 陣列中的索引值
// 使用 Array.splice(index, num)方法刪除回調函數
const unsubscribe = () => {
const index = cbs.indexOf(cb);
if (index >= 0 ) {
cbs.splice(index, 1);
}
return undefined;
}
return { msg: "subscribed", unsubscribe: unsubscribe };
}
// `emit`觸發邏輯
emit(event, args) {
let results = [];
//Map中key不存在時返回空陣列
if (!this.events.has(event)) {
return results;
}
//傳回按順序調用cbs的結果陣列
const cbs = this.events.get(event);
for (const cb of cbs) {
results.push(cb(...args));
}
return results;
}
}
let test1 =[];
const emitter1 = new EventEmitter();
test1[1]=emitter1.emit("firstEvent",[]);
test1[2]=emitter1.subscribe("firstEvent", function cb1() { return 5; });
test1[3]=emitter1.subscribe("firstEvent", function cb2() { return 6; });
test1[4]=emitter1.emit("firstEvent",[]);
console.log(`[test1] ${JSON.stringify(test1)}`);
//[test1] [null,[],{"msg":"subscribed"},{"msg":"subscribed"},[5,6]]
let test2 =[];
let emitter2 = new EventEmitter();
test2[1]=emitter2.subscribe("firstEvent", function cb1(...args) { return args.join(','); });
test2[2]=emitter2.emit("firstEvent", [1, 2, 3]);
test2[3]=emitter2.emit("firstEvent", [3, 4, 6]);
console.log(`[test2] ${JSON.stringify(test2)}`);
//[test2] [null,{"msg":"subscribed"},["1,2,3"],["3,4,6"]]
let test3 =[];
const emitter3 = new EventEmitter();
const sub = emitter3.subscribe("firstEvent", (...args) => args.join(','));
test3[1]= sub;
test3[2]= emitter3.emit("firstEvent", [1, 2, 3]);
test3[3]= sub.unsubscribe();
test3[4]= emitter3.emit("firstEvent", [4, 5, 6]);
console.log(`[test3] ${JSON.stringify(test3)}`);
//[test3] [null,{"msg":"subscribed"},["1,2,3"],null,[]]
let test4 =[];
const emitter4 = new EventEmitter();
const sub1 = emitter4.subscribe("firstEvent", x => x + 1);
test4[1]=sub1;
const sub2 = emitter4.subscribe("firstEvent", x => x + 2);
test4[2]=sub2;
test4[3]=sub1.unsubscribe();
test4[4]= emitter4.emit("firstEvent", [5]);
console.log(`[test4] ${JSON.stringify(test4)}`);
//[test4] [null,{"msg":"subscribed"},{"msg":"subscribed"},null,[7]]